﻿//Copyright (c) Microsoft Corporation
//
//All rights reserved. 
//
//Licensed under the Apache License, Version 2.0 (the ""License""); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.Table;
using Windows.Storage;

namespace TED.WindowsAzure.Unplugged.Mobile.Tests.Helpers
{
    /// <summary>
    /// Creates test data in an associated Azure Storage Account
    /// </summary>
    public class CloudBlobHelper
    {
        private readonly string _containerName;
        private Random _random = new Random();
        private CloudBlobClient _cloudBlobClient;
        private CloudTableClient _cloudTableClient;
        //TODO empty storage key
        private string _storageKey = "[REPLACE with Storage Account Key]";
        private string _storageAccount = "[REPLACE with Storage Account Name]";

        public CloudBlobHelper(string containerName)
        {
            _containerName = containerName;
            _cloudBlobClient = new CloudBlobClient(
                new Uri("[REPLACE with Mobile Services Account URL]"),
                new StorageCredentials(_storageAccount, _storageKey));

            _cloudTableClient = new CloudTableClient(
                new Uri( "[REPLACE with Mobile Services Account URL]" ),
                new StorageCredentials(_storageAccount, _storageKey));
        }

        public async Task FillBlobStorage(int amountOfFiles)
        {
            var container = _cloudBlobClient.GetContainerReference(_containerName);
            await container.CreateIfNotExistsAsync();

            var blobRequestOptions = new BlobRequestOptions()
            {
                MaximumExecutionTime = new TimeSpan(0, 30, 0),
                ServerTimeout = new TimeSpan(0, 30, 0)
            };

            var accessCondition = AccessCondition.GenerateEmptyCondition();
            var operationContext = new OperationContext();

            for (int i = 0; i < amountOfFiles; i++)
            {
                var file = container.GetBlockBlobReference(string.Format("{0}.txt", i));
                await file.UploadTextAsync(Ipsum.GetPhrase(_random.Next(0, 1000)), accessCondition, blobRequestOptions, operationContext);
            }
        }

        public async Task FillBlobStorage( int amountOfFiles, int wordcount )
        {
            var container = _cloudBlobClient.GetContainerReference( _containerName );
            await container.CreateIfNotExistsAsync();

            var blobRequestOptions = new BlobRequestOptions()
            {
                MaximumExecutionTime = new TimeSpan(0, 30, 0),
                ServerTimeout = new TimeSpan(0, 30, 0)
            };

            var accessCondition = AccessCondition.GenerateEmptyCondition();
            var operationContext = new OperationContext();

            for (int i = 0; i < amountOfFiles; i++)
            {
                var file = container.GetBlockBlobReference( string.Format( "{0}.txt", i ) );
                await file.UploadTextAsync(Ipsum.GetPhrase(wordcount), accessCondition, blobRequestOptions, operationContext);
            }
        }

        public async Task CleanUpBlob()
        {
            var container = _cloudBlobClient.GetContainerReference(_containerName);
            await container.DeleteIfExistsAsync();
        }

        public async Task<int> GetBlobCount()
        {
            var container = _cloudBlobClient.GetContainerReference(_containerName);
            var result = await container.ListBlobsSegmentedAsync("", true, BlobListingDetails.All, 1000, null,
                new BlobRequestOptions(), null);
            
            return result.Results.Count();
        }

        public async Task EmptyTestDirectory()
        {
            IStorageFolder basefolder = Windows.Storage.ApplicationData.Current.LocalFolder;
           
            var testfolder = await basefolder.GetFolderAsync( "test-" + _containerName );
            await testfolder.DeleteAsync();
        }

        public async Task<TimeSpan> DownloadAllBlobs()
        {
            var startTime = System.DateTime.UtcNow;

            CloudBlobContainer container = _cloudBlobClient.GetContainerReference(_containerName);
            
            IStorageFolder basefolder = Windows.Storage.ApplicationData.Current.LocalFolder;
            
            var testfolder = await basefolder.CreateFolderAsync( "test-" + _containerName );
            string filename;

            BlobContinuationToken continuationToken = null;
            string prefix = null;
            //bool useFlatBlobListing = true;
            //BlobListingDetails blobListingDetails = BlobListingDetails.Metadata;
            //int maxBlobsPerRequest = 2000;
            List<IListBlobItem> blobs = new List<IListBlobItem>();
            do
            {
                //var listingResult = await container.ListBlobsSegmentedAsync(prefix, useFlatBlobListing, blobListingDetails, maxBlobsPerRequest, continuationToken, null, null);
                var listingResult = await container.ListBlobsSegmentedAsync( prefix, continuationToken );
                continuationToken = listingResult.ContinuationToken;
                blobs.AddRange( listingResult.Results );
            } while (continuationToken != null);

            for (int i = 0; i < blobs.Count(); i++)
            {
                filename = string.Format( "{0}.txt", i );

                CloudBlockBlob blockBlob = container.GetBlockBlobReference( filename );

                StorageFile file = await testfolder.CreateFileAsync( filename );
                await blockBlob.DownloadToFileAsync( file );
            }
            var endTime = System.DateTime.UtcNow;
            return endTime - startTime;
        }

        internal async Task<StorageFile> DownloadSingleBlob( string filename )
        {
            CloudBlobContainer container = _cloudBlobClient.GetContainerReference( _containerName );

            IStorageFolder basefolder = Windows.Storage.ApplicationData.Current.LocalFolder;
            var testfolder = await basefolder.CreateFolderAsync( "test-" + _containerName );

            CloudBlockBlob blockBlob = container.GetBlockBlobReference( filename );

            StorageFile file = await testfolder.CreateFileAsync( filename );
            await blockBlob.DownloadToFileAsync( file );
            return file;
        }

        public class PerfResult
        {
            public PerfResult( string testname, TimeSpan nativetime, TimeSpan unpluggedtime, int numfiles, int size )
            {
                TestName = testname;
                NativeTime = nativetime;
                UnpluggedTime = unpluggedtime;
                NumFiles = numfiles;
                Size = size;
            }

            /// <summary>
            /// Name of test
            /// </summary>
            public string TestName { get; set; }

            /// <summary>
            /// Time to perform operation using standard Windows Azure SDK
            /// </summary>
            public TimeSpan NativeTime { get; set; }

            /// <summary>
            /// Time to perform operation using Unplugged
            /// </summary>
            public TimeSpan UnpluggedTime { get; set; }

            /// <summary>
            /// Number of files to test
            /// </summary>
            public int NumFiles { get; set; }

            /// <summary>
            /// Size of files to test
            /// </summary>
            public int Size { get; set; }
        }
    }
}
